/*
 * title: axios请求方式的封装
 * date: 2019-05-15
 * author: wjh
 */

import Vue from 'vue'
import router from '@/router'
import axios from 'axios'
import { Notification } from 'element-ui'
import store from '@/store'
import apiConfig from '@/api/apiConfig'

/**
 * 请求失败后的错误统一处理
 */
const errorHandle = (data) => {
  const arr = [
    apiConfig.code.authFail // 权限认证失败  code.authFail=2
  ]
  if (arr.includes(data.code)) {
    router.replace({
      path: '/login',
      query: {
        redirect: router.currentRoute.fullPath,
        name: router.currentRoute.name
      }
    })
  }
}

axios.defaults.withCredentials = true // 允许携带cookie
axios.defaults.timeout = 60000 // 超时时间

/**
 * 请求拦截器
 */
axios.interceptors.request.use(
  config => {
    // 登录流程控制中，根据本地是否存在token判断用户的登录情况
    // 但是即使token存在，也有可能token是过期的，所以在每次的请求头中携带token
    // 后台根据携带的token判断用户的登录情况，并返回给我们对应的状态码
    // 而后我们可以在响应拦截器中，根据状态码进行一些统一的操作。
    const token = store.state.user.operator.token;
    if (token) {
      config.headers.Authorization = token
    }
    return config
  },
  error => {
    errorHandle(error)
    Promise.reject(error)
  }
)

/**
 * 响应拦截器
 */
axios.interceptors.response.use(
  response => {
    if (response.status === 200) {
      errorHandle(response.data)
      return Promise.resolve(response.data)
    } else {
      return Promise.reject(response.data)
    }
  },
  error => {
    if (error) {
      errorHandle(error)
      return Promise.reject(error)
    } else {
      this.$Tips()
    }
  }
)

/**
 * request 请求方法
 */
const request = {
  async getData(url, params, hint = true) {
    const data = await request.get(url, params, hint, 'data') // get请求(直接返回结果)
    return data
  },
  async postData(url, params, hint = true) {
    const data = await request.post(url, params, hint, 'data') // post请求(直接返回结果)
    return data
  },
  async putData(url, params, hint = true) {
    const data = await request.put(url, params, hint, 'data') // put请求(直接返回结果)
    return data
  },
  async getCode(url, params, hint = true) {
    const data = await request.get(url, params, hint, 'code') // get请求(直接返回code编码)
    return data
  },
  async postCode(url, params, hint = true) {
    const data = await request.post(url, params, hint, 'code') // post请求(直接返回结果,失败不提示)
    return data
  },
  async putCode(url, params, hint = true) {
    const data = await request.put(url, params, hint, 'code') // put请求(直接返回结果,失败不提示)
    return data
  },
  async get(url, params, hint, result) {
    if (!hint && !result) {
      hint = false
    }
    let config = {
      url,
      params,
      hint,
      result
    }
    config.method = 'GET'
    const data = await request.request(config) // get请求
    return data
  },
  async post(url, params, hint, result) {
    if (!hint && !result) {
      hint = false
    }
    let config = {
      url,
      params,
      hint,
      result
    }
    config.method = 'POST'
    config.mode = 'no-cors' // 设置无cors
    const data = await request.request(config) // post请求
    return data
  },
  async put(url, params, hint, result) {
    if (!hint && !result) {
      hint = false
    }
    let config = {
      url,
      params,
      hint,
      result
    }
    config.method = 'PUT'
    config.mode = 'no-cors' // 设置无cors
    const data = await request.request(config) // put请求
    return data
  },
  async DELETE(url, params, hint, result) {
    if (!hint && !result) {
      hint = false
    }
    let config = {
      url,
      params,
      hint,
      result
    }
    config.method = 'DELETE'
    const data = await request.request(config)
    return data
  },
  request(config) {
    let { url, method, params, hint, result } = config
    if (url.includes('http')) {
      config.url = url
    } else {
      const nodeEnv = process.env.NODE_ENV
      // TODO
      // const stage = process.env.STAGE || 'local'
      // const prefix = (nodeEnv === 'production' || stage === 'local') ? '/' : '/proxy/'
      const prefix = (nodeEnv === 'production') ? '/' : '/proxy/'
      config.url = `${prefix}${url}`
    }
    if (method === 'POST' || method === 'PUT') {
      config.data = params
      delete config.params
    }
    return new Promise(async resolve => {
      try {
        const res = await axios(config)
        const type = (res.code === apiConfig.code.success) ? 'success' : 'error'
        // 当查询成功,并且不是get请求才显示消息提示
        if (type === 'success') {
          if (method !== 'GET') {
            this.Tips(hint, res.message, type)
          }
        } else {
          this.Tips(true, res.message, type)
        }
        this.resultHandle(resolve, res, result)
      } catch (error) {
        let data = error.response
        this.Tips(true, data.data.message || apiConfig.system.connectionFail, 'error', data.data.code)
        if (result === 'data') {
          resolve()
        } else {
          resolve(error)
        }
      }
    })
  },
  resultHandle(resolve, res, result) {
    if (res.code === apiConfig.code.success) {
      if (result === 'code') {
        resolve(true)
      } else if (result === 'data') {
        resolve(res.data)
      } else {
        resolve(res)
      }
    } else {
      if (result === 'code') {
        resolve(res.code)
      } else if (result === 'data') {
        resolve('')
      } else {
        resolve(res)
      }
    }
  },
  Tips(hint, message = apiConfig.system.exception, type, title = '标题') {
    const notHintArr = [false, 'silence'] // 此数组中的类型,失败不会提示
    if (!notHintArr.includes(hint)) {
      let showClose = true
      Notification.closeAll()
      Notification({ type, title, message, showClose, duration: 2000 })
    }
  }
}

for (let item in request) {
  if (item.indexOf('get') >= 0 || item.indexOf('post') >= 0 || item.indexOf('put') >= 0) {
    Vue.prototype[`$${item}`] = request[item]
  }
}

Vue.prototype.$DELETE = request.DELETE

export default request
